#pragma once

#include <memory>
#include <vector>

namespace nef {

class Catalog;

// Basic implementation for non-pointer types
template<typename T>
class part_composer
{
public:
	static void compose(Catalog &cat, T &val)
	{
		cat.SatisfyImports(val);

		CallImportsSatisfied(val);

		cat.StoreExports(val);
	}
};

// Partial specialization for raw pointers
template<typename T>
class part_composer<T*>
{
public:
	static void compose(Catalog &cat, T *val)
	{
		if (!val)
			return;

		part_composer<T>::compose(cat, *val);
	}
};

// Partial specialization for shared pointers
template<typename T>
class part_composer<std::shared_ptr<T>>
{
public:
	static void compose(Catalog &cat, const std::shared_ptr<T> &val)
	{
		if (!val)
			return;

		part_composer<T>::compose(cat, *val);
	}
};

// Partial specialization for weak pointers
template<typename T>
class part_composer<std::weak_ptr<T>>
{
public:
	static void compose(Catalog &cat, const std::weak_ptr<T> &val)
	{
		auto spVal = val.lock();

		part_composer<decltype(spVal)>::compose(cat, spVal);
	}
};



// Utility specialization for vectors, this allows you to compose multiple parts at the same time
template<typename T>
class part_composer<std::vector<T>>
{
public:
	static void compose(Catalog &cat, std::vector<T> &vals)
	{
		for (T &val : vals)
			part_composer<T>::compose(cat, val);
	}
};

}